<?php

class ImageProcessingException extends Exception {};

/**
 * Description of ImageProcessing
 *
 * @author Martin Grossmann <snake.aas@gmail.com>
 * @version 1.0
 * @package ImageProcessing
 * 
 *
 * @TODO: Add picture size validation
 */
class ImageProcessing {
  
  const IMAGE_PORTRAIT = 1;
  const IMAGE_LANDSCAPE = 2;
  
  const THUMBNAIL_SIDE = 200;
  const ORIGINAL_SIDE = 800;
  
  
  private $inputFileName;
  private $outputFileName;
  private $imageType;
  private $imageWidth;
  private $imageHeight;
  private $imageSize;
  private $imageName;
  private $imageOrientation;
  private $imageRotation = 1;
  
  private $parameters = null;
  
  private static $exifParams = array('Make'             => 'Make', 
                                     'Model'            => 'Model', 
                                     'ExposureTime'     => 'Exposure Time', 
                                     'ApertureValue'    => 'Aperture Number', 
                                     //'ISOSpeedRatings'  => 'ISO', 
                                     'FocalLength'      => 'Focal Length', 
                                     'DateTimeOriginal' => 'Time taken photo');
 private $db; 
 
  
  public function __construct(\Doctrine\ORM\EntityManager &$db, $fileName) {
    $this->db = $db;   
    $this->inputFileName = $fileName;        
  }
  

  public function getProperties() {
    $exifImageType = exif_imagetype($this->inputFileName);    
    
    if ($exifImageType !== false) {                    
      $this->imageType = $exifImageType;
      $infoReaded = $this->readExif(); 
      //var_dump($infoReaded);
    } 
    
    if (!$infoReaded) {
      $tmp = getimagesize($fileName);
      $this->imageType   = $tmp[2];    
      $this->imageHeight = $tmp[1];
      $this->imageWidth  = $tmp[0];
      $this->imageSize   = filesize($fileName);
      $this->imageName   = substr(basename($fileName), 0, strrpos(basename($fileName), "."));  
    }
    
    $this->imageOrientation = ($this->imageWidth > $this->imageHeight) ? self::IMAGE_LANDSCAPE : self::IMAGE_PORTRAIT;
    
    $dir = 'directory'.mt_rand(1, 20).'/';
    //$dir = 'directory2/';
    do {
      $file = $this->generateName(8);
      $this->outputFileName = $dir.$file.image_type_to_extension($this->imageType);
    } while (file_exists(Photo::THUMBNAIL_PATH.$this->outputFileName));
    
    if(!file_exists(Photo::THUMBNAIL_PATH.$dir)) mkdir(Photo::THUMBNAIL_PATH.$dir);
    if(!file_exists(Photo::ORIGINAL_PATH.$dir)) mkdir(Photo::ORIGINAL_PATH.$dir);
  }
    
  private function readExif() {
         
    $exif = @read_exif_data($this->inputFileName);
    
    if ($exif === false) return false;
      //var_dump($exif);
      //echo $exif["Orientation"].nl;
    $this->imageWidth = $exif['COMPUTED']['Width'];
    $this->imageHeight = $exif['COMPUTED']['Height'];
    $this->imageSize = $exif['FileSize'];
    $this->imageName = substr($exif['FileName'], 0, strrpos($exif['FileName'], '.'));
    $this->imageRotation = isset($exif['Orientation']) ? $exif['Orientation'] : 1;
    
    $i=0;
    foreach(self::$exifParams as $fromExif => $toDatabase) {
      if(!isset($exif[$fromExif])) continue;
      $this->parameters[$i] = new PhotosParameters();
      $this->parameters[$i]->Parameter = $this->db->find('Parameter', $toDatabase);
      $this->parameters[$i]->Value = $exif[$fromExif];
    }

    return true;
  }
  
  public function generateName($length) {
    $chars = 'abcdef1234567890';
    $return = '';	 
	  for ($i = 0; $i < $length; $i++) {
      $return .= $chars{mt_rand(0,6)};
		}
    return $return;
  }  
  
  public function saveToDB(Album &$album, $name = null, $description = null) {
    /*
     * vyčíst relevantní exif informace
     * zmenšit obrázek na přijatelnou hodnotu
     * vytvořit miniaturu
     * zapsat data na disk
     * zapsat data do db
     * změnit počet fotek v albu 
     */
    
    
    $photo = new Photo();
    $photo->Name = ($name == null) ? $this->imageName : substr(basename($name), 0, strrpos(basename($name), "."));;
    $photo->Album = $album;
    $photo->ThumbnailUNC = Photo::THUMBNAIL_PATH.$this->outputFileName;
    $photo->FileUNCPath  = Photo::ORIGINAL_PATH.$this->outputFileName;
    $photo->FileWidth = $this->imageWidth;
    $photo->FileHeight = $this->imageHeight;    
    $photo->FileSize = $this->imageSize;
    $photo->FileMimeType = $this->db->find('MimeType', image_type_to_mime_type($this->imageType));
    $photo->Description = $description;
    $photo->AverageRating = 0.0;
    $photo->RatingsCount = 0;
    
    if($this->parameters != null)
      foreach($this->parameters as $param)
        $photo->addParameter($param);
    
    $photo->Album->PhotoCount++;
    
    $this->db->persist($photo);
    $this->db->flush();
  }
  
  public function saveToDisk() {
    
    if ($this->imageOrientation == self::IMAGE_LANDSCAPE) {
      $originalWidth = self::ORIGINAL_SIDE;
      $originalHeight = round(($this->imageHeight * $originalWidth) / $this->imageWidth);      
    } else {
      $originalHeight = self::ORIGINAL_SIDE;
      $originalWidth = round(($this->imageWidth * $originalHeight) / $this->imageHeight);
    }
            
    $original = imagecreatetruecolor($originalWidth, $originalHeight);
    
    switch ($this->imageType) {
      case IMAGETYPE_JPEG:
        $image = imagecreatefromjpeg($this->inputFileName);
        break;
    
      case IMAGETYPE_PNG:
        $image = imagecreatefrompng($this->inputFileName);
        break;
      
      case IMAGETYPE_GIF:
        $image = imagecreatefromgif($this->inputFileName);
        break;
      
      default: throw new ImageProcessingException(T_('Unsupported type of image'));
    }
    
    imagecopyresampled($original, $image, 0, 0, 0, 0, $originalWidth, $originalHeight, $this->imageWidth, $this->imageHeight);    
    
    imagedestroy($image);      
    $image = null;
    
    $this->imageWidth = $originalWidth;
    $this->imageHeight = $originalHeight;
    
    
    $this->exifRotation($original, $this->imageRotation); 
    
    $thumbnailWidth = round($this->imageWidth / 4);
    $thumbnailHeight = round($this->imageHeight / 4);
    
    $thumbnail = imagecreatetruecolor($thumbnailWidth, $thumbnailHeight);              
    imagecopyresampled($thumbnail, $original, 0, 0, 0, 0, $thumbnailWidth, $thumbnailHeight, $this->imageWidth, $this->imageHeight);    
    
    
    switch ($this->imageType) {
      case IMAGETYPE_JPEG:
        imagejpeg($thumbnail, Photo::THUMBNAIL_PATH.$this->outputFileName, 75);
        imagejpeg($original, Photo::ORIGINAL_PATH.$this->outputFileName, 100);
        break;
    
      case IMAGETYPE_PNG:
        imagepng($thumbnail, Photo::THUMBNAIL_PATH.$this->outputFileName, 2);
        imagepng($original, Photo::ORIGINAL_PATH.$this->outputFileName, 0);
        break;
      
      case IMAGETYPE_GIF:
        imagegif($thumbnail, Photo::THUMBNAIL_PATH.$this->outputFileName);
        imagegif($original, Photo::ORIGINAL_PATH.$this->outputFileName);
        break;
      
      default: throw new ImageProcessingException(T_('Unsupported type of image'));
    }
    
    $this->imageSize = filesize(Photo::ORIGINAL_PATH.$this->outputFileName);
    //imagejpeg($thumbnail, Photo::THUMBNAIL_PATH.$this->outputFileName, 75);      
    //imagejpeg($thumbnail, $this->inputFileName.'.jpg', 75);      
   
    imagedestroy($thumbnail);
    $thumbnail = null;
    
    imagedestroy($original);      
    $image = null;
    
    
    return Photo::ORIGINAL_PATH.$this->outputFileName;
  }
  
  
  public function exifRotation(&$image, $exifRotation){
    switch ($exifRotation) {      
      case 1: // do Nothing
        break;      
      
      case 2: // flip horizontal
        break;      
      
      case 3: // rotate 180
        $image = imagerotate($image, 180, 0);
        $this->imageRotation = 1;
        break;      
      
      case 4: // flip vertical        
        break;      
      
      case 5: // transpose        
        break;      
      
      case 6: // rotate 270     
        $image = imagerotate($image, 270, 0);
        
        $this->imageWidth ^= $this->imageHeight;
        $this->imageHeight ^= $this->imageWidth;
        $this->imageWidth ^= $this->imageHeight;
        
        $this->imageRotation = 1;
        break;
      
      case 7: // transverse     
        break;      
      
      case 8: // rotate 90
        $image = imagerotate($image, 90, 0);
        
        $this->imageWidth ^= $this->imageHeight;
        $this->imageHeight ^= $this->imageWidth;
        $this->imageWidth ^= $this->imageHeight;
        
        $this->imageRotation = 1;
        break;            
    }
  }
}

?>
